package com.me.extend.ctx

import android.annotation.SuppressLint
import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Process
import android.provider.Settings
import android.util.Log
import androidx.annotation.AnimRes
import com.me.extend.services.activityManager
import com.me.extend.version.getPackageName


inline fun <reified A : Activity> Context.start(configIntent: Intent.() -> Unit = {}) {
    startActivity(Intent(this, A::class.java).apply(configIntent))
}

inline fun Context.start(action: String, configIntent: Intent.() -> Unit = {}) {
    startActivity(Intent(action).apply(configIntent))
}

inline fun <reified A : Activity> Context.start(vararg params: Pair<String, Any?>) {
    startActivity(Intent(this, A::class.java).apply {
        put(params)
    })
}

fun Context.start(action: String, vararg params: Pair<String, Any?>) {
    startActivity(Intent(action).apply {
        put(params)
    })
}

fun finishActivity(activity: Activity, isLoadAnim: Boolean = false) {
    activity.finish()
    if (!isLoadAnim) {
        activity.overridePendingTransition(0, 0)
    }
}

fun finishActivity(
    activity: Activity,
    @AnimRes enterAnim: Int,
    @AnimRes exitAnim: Int
) {
    activity.finish()
    activity.overridePendingTransition(enterAnim, exitAnim)
}


fun isAppRunning(pkgName: String): Boolean {
    if (pkgName.isBlank()) {
        return false
    }
    val pm = appCtx.packageManager
    val pi = pm.getPackageInfo(pkgName, 0)
    val uid = pi.applicationInfo.uid
    val am: ActivityManager = activityManager
    val taskInfo = am.getRunningTasks(Int.MAX_VALUE)
    if (taskInfo != null && taskInfo.size > 0) {
        for (aInfo: ActivityManager.RunningTaskInfo in taskInfo) {
            if (aInfo.baseActivity != null) {
                if (pkgName == aInfo.baseActivity!!.packageName) {
                    return true
                }
            }
        }
    }
    val serviceInfo = am.getRunningServices(Int.MAX_VALUE)
    if (serviceInfo != null && serviceInfo.size > 0) {
        for (aInfo: ActivityManager.RunningServiceInfo in serviceInfo) {
            if (uid == aInfo.uid) {
                return true
            }
        }
    }
    return false
}

fun getLaunchAppIntent(packageName: String): Intent? {
    if (packageName.isBlank()) {
        return null
    }
    val launcherActivity: String = getLauncherActivity(packageName)
    if (launcherActivity.isBlank()) {
        return null
    }
    val intent = Intent(Intent.ACTION_MAIN)
    intent.addCategory(Intent.CATEGORY_LAUNCHER)
    intent.setClassName(packageName, launcherActivity)
    return intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}

@SuppressLint("QueryPermissionsNeeded")
fun getLauncherActivity(packageName: String): String {
    if (packageName.isBlank()) {
        return ""
    }
    val intent = Intent(Intent.ACTION_MAIN, null)
    intent.addCategory(Intent.CATEGORY_LAUNCHER)
    intent.setPackage(packageName)
    val pm: PackageManager = appCtx.packageManager
    val info = pm.queryIntentActivities(intent, 0)
    return if (info.size == 0) {
        ""
    } else {
        info[0].activityInfo.name
    }
}

fun launchApp(packageName: String) {
    if (packageName.isBlank()) {
        return
    }

    val launchAppIntent: Intent? = getLaunchAppIntent(packageName)
    if (launchAppIntent == null) {
        Log.e("AppUtils", "Didn't exist launcher activity.")
        return
    }
    appCtx.startActivity(launchAppIntent)
}

/**
 * Relaunch the application.
 */
fun relaunchApp() {
    relaunchApp(false)
}

/**
 * Relaunch the application.
 *
 * @param isKillProcess True to kill the process, false otherwise.
 */
fun relaunchApp(isKillProcess: Boolean) {
    val intent: Intent? = getLaunchAppIntent(getPackageName())
    if (intent == null) {
        Log.e("AppUtils", "Didn't exist launcher activity.")
        return
    }
    intent.addFlags(
        Intent.FLAG_ACTIVITY_NEW_TASK
                or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK
    )
    appCtx.startActivity(intent)
    if (!isKillProcess) return
    Process.killProcess(Process.myPid())
    System.exit(0)
}

fun launchAppDetailsSettings() {
    launchAppDetailsSettings(getPackageName())
}

private fun getIntent(intent: Intent, isNewTask: Boolean): Intent? {
    return if (isNewTask) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) else intent
}

fun getLaunchAppDetailsSettingsIntent(pkgName: String, isNewTask: Boolean): Intent? {
    if (pkgName.isBlank()) {
        return null
    }
    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
    intent.data = Uri.parse("package:$pkgName")
    return getIntent(intent, isNewTask)
}

@SuppressLint("QueryPermissionsNeeded")
fun isIntentAvailable(intent: Intent?): Boolean {
    if (intent == null) {
        return false
    }
    return appCtx.packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size > 0
}

fun launchAppDetailsSettings(packageName: String) {
    if (packageName.isBlank()) {
        return
    }

    val intent = getLaunchAppDetailsSettingsIntent(packageName, true)
    if (!isIntentAvailable(intent)) return
    appCtx.startActivity(intent)
}

/**
 * Launch the application's details settings.
 *
 * @param activity    The activity.
 * @param requestCode The requestCode.
 */
fun launchAppDetailsSettings(activity: Activity?, requestCode: Int) {
    launchAppDetailsSettings(activity, requestCode, getPackageName())
}

/**
 * Launch the application's details settings.
 *
 * @param activity    The activity.
 * @param requestCode The requestCode.
 * @param pkgName     The name of the package.
 */
fun launchAppDetailsSettings(activity: Activity?, requestCode: Int, pkgName: String) {
    if (activity == null || pkgName.isBlank()) return
    val intent = getLaunchAppDetailsSettingsIntent(pkgName, false)
    if (!isIntentAvailable(intent)) return
    activity.startActivityForResult(intent, requestCode)
}

/**
 * Exit the application.
 */
fun exitApp() {
    System.exit(0)
}


